from pyrem_torq.utility import to_codepoint_list, SingletonWoInitArgs

class NodeFormatting(object):
    __slots__ = []
    def is_recursive(self, node): return True
    def in_format(self, node): return None
    def out_format(self, node): return None
    
    def get_infos(self, node):
        return ( self.isis_recursive(node), self.in_format(node), self.out_format(node) )

def collect_leaves(node):
    r = []; r_append = r.append
    def c_i(node):
        for item in node[1:]:
            (c_i if isinstance(item, list) else r_append)(item)
    c_i(node)
    return r

def __make_ascii_cp_to_str():
    __escapeTable = { '\a': '&a;', '\b': '&b;', 
            '\f': '&f;', '\n': '&n;', '\r': '&r;', '\t': '&t;', '\v': '&v;',
            '\\': '&bslash;', "'": '&squot;', '"': '&quot;',
            '&': '&amp;', '<': '&lt;', '>': '&gt;', '\xa0': "&nbsp;" }

    ary = []
    for cp in xrange(0, 0x100):
        c = chr(cp)
        v = __escapeTable.get(c)
        ary.append(v if v is not None else \
                c if '\x20' <= c <= '\x7f' else \
                "&x%x;" % cp)
    return tuple(ary)

__asciiCodePointToStr = __make_ascii_cp_to_str()

def escape_str(s):
    return "".join((__asciiCodePointToStr[cp] if cp < 0x100 else "&x%x;" % cp) \
            for cp in to_codepoint_list(s))

class NodeFormatString(NodeFormatting):
    __slots__ = [ '__begin', '__end' ]
    def __init__(self, formatStr):
        self.__begin, _, self.__end = formatStr.partition("%s")
    
    def in_format(self, node):
        return self.__begin + escape_str(u"".join(collect_leaves(node))) + self.__end
            
    def is_recursive(self, node): return False
    
    def get_infos(self, node):
        return ( False, self.in_format(node), None )

class NodeString(NodeFormatting):
    __slots__ = [ '__string' ]
    def __init__(self, s):
        self.__string = s
    
    def in_format(self, node):
        return self.__string
            
    def is_recursive(self, node): return False
    
    def get_infos(self, node):
        return ( False, self.__string, None )

class NodeHide(NodeFormatting): # singleton
    __metaclass__ = SingletonWoInitArgs
    __slots__ = [ ]
    def is_recursive(self, node): return False
    def get_infos(self, node): return ( False, None, None )

class NodeRecurse(NodeFormatting):
    __slots__ = [ 'inText', 'outText' ]
    def __init__(self, inText, outText):
        self.inText, self.outText = inText, outText
    
    def in_format(self, node): return self.inText
    def out_format(self, node): return self.outText
    def get_infos(self, node): return ( True, self.inText, self.outText )

class NodeFlatten(NodeFormatting): # singleton
    __metaclass__ = SingletonWoInitArgs
    __slots__ = [ ]
    def get_infos(self, node): return ( True, None, None )

class NodeName(NodeFormatting): # singleton
    __metaclass__ = SingletonWoInitArgs
    __slots__ = [ ]
    def in_format(self, node): return node[0]
    def is_recursive(self, node): return False
    def get_infos(self, node): return ( False, node[0], None )

def format_seq(seq, nodeFormatterTable):
    if not isinstance(seq, list): return
    r = []; r_append = r.append
    def fs_i(node):
        r, i, o = nodeFormatterTable[node[0]].get_infos(node)
        if i is not None: r_append(( i, node ))
        if r:
            for item in node[1:]:
                if isinstance(item, list):
                    fs_i(item)
        if o is not None: r_append(( o, node ))
    fs_i(seq)
    return r

# you can use this, but slow :-(
def format_seq_iter(seq, nodeFormatterTable):
    if not isinstance(seq, list): return
    def fs_i(node):
        r, i, o = nodeFormatterTable[node[0]].get_infos(node)
        if i is not None: yield i, node
        if r:
            for item in node[1:]:
                if isinstance(item, list):
                    for v in fs_i(item): yield v
        if o is not None: yield o, node
    return fs_i(seq)
